package Controller;

import Model.StatisticalReport.*;
import Service.StatisticalReport.*;
import net.sf.oval.ConstraintViolation;
import net.sf.oval.Validator;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;

import org.springframework.web.multipart.MultipartFile;
import utils.ResponseBody.ResponseStatus;
import utils.ResponseBody.JsonResponse;
import utils.pages.PageBean;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.*;

@Controller
@RequestMapping("/report")
public class ReportController {

    private static final Logger logger = LoggerFactory.getLogger(ReportController.class);
    private static final Validator validator = new Validator();
    private final int ERROR_COUNT_THRESHOLD = 12;
    private final int PAGE_MAX_NUM = 24; //面页最大记录数

    @Resource
    ReportServiceFactory reportServiceFactory;

    @Resource
    ReportStatisticsService reportStatisticsService;

    @Resource
    ReportUpdateService reportUpdateService;

//    private static void getReportInfo(){
//    }

    /**
     * 返回参数错误
     * @param result
     * @return
     */
    private JsonResponse returnParamError(JsonResponse result, String msg){
        result.setCode(ResponseStatus.PARAM_ERROR);
        if(msg == null){
            msg = "参数有误";
        }
        result.setMsg(msg);
        return result;
    }

    @RequestMapping("/")
    public String toIndex(){
        logger.debug("转到index");
        return "/YiBaoMonitor/StatisticalReport/index";
    }

    @RequestMapping("/toDataOverview")
    public String toDataOverview(Model model){

//        final List<Map<>>
        logger.debug("转到数据总览");
        //上传响应错误代码
//        model.addAttribute("uploadDetailResponseStatus", UploadDetailResponse.Status.getValues());
        return "YiBaoMonitor/StatisticalReport/data-overview";
    }

    @RequestMapping("/toUploadFile")
    public String toUploadFile(Model model){
        logger.debug("转到数据导入");
        //上传响应错误代码
        model.addAttribute("uploadDetailResponseStatus", UploadDetailResponse.Status.getValues());
        return "YiBaoMonitor/StatisticalReport/data-import";
    }

    @RequestMapping("/toStatistics")
    public String toStatistics(Model model, @RequestParam(value = "reportId")int reportId){
        logger.debug("转到数据导入");
//        ReportClass reportClass = ReportClass.get(reportId);
        //上传响应错误代码currentReportId
        System.out.println(reportId);
        model.addAttribute("individualClass",IndividualClass.getValues());
        model.addAttribute("currentReportId", reportId);
        return "YiBaoMonitor/StatisticalReport/statistics";
    }


    @RequestMapping("/toSettlement")
    public String toSettlement(){
        logger.debug("toSettlement");
        return "YiBaoMonitor/StatisticalReport/settlement";
    }

    @RequestMapping("/toExpense")
    public String toExpense(){
        logger.debug("toSettlement");
        return "YiBaoMonitor/StatisticalReport/expense";
    }

    @RequestMapping("/toMonthly")
    public String toMonthly(){
        logger.debug("toMonthly");
        return "YiBaoMonitor/StatisticalReport/monthly";
    }

    /**
     * 保存列表到数据库
     * @param list
     * * @param result
     * @return
     */
    private UploadDetailResponse upload(List<Report> list, ReportClass reportClass, IndividualClass idvClass){
        int errorCount = 0;
        //错误信息
        UploadDetailResponse payload = new UploadDetailResponse();

        //按月份统计
        Map<Date, List<Report>> dateMap = new HashMap<>();
        for(Report each: list){
            //数据有效性校验
            //Validator validator = new Validator();
            List<ConstraintViolation> ret = validator.validate(each);
            if(ret.size() > 0){
                payload.addValidatorError(ret);
                //if(payload.getValidatorError().size())
                errorCount++;
                if(errorCount > ERROR_COUNT_THRESHOLD){
                    //超过校验失败上线,返回错误
                    payload.setStatus(UploadDetailResponse.Status.TOO_MANY_VIOLATION_ERROR);
                    return payload;
                }
                continue;
            }
            List<Report> details = dateMap.get(each.getDAA());
            if(details == null){
                details = new ArrayList<>();
                dateMap.put(each.getDAA(), details);
            }
            details.add(each);
        }

        ReportService reportService = reportServiceFactory.getReportService(reportClass);

        //查重
        errorCount = 0;
        for(Date date: dateMap.keySet()){
            if(reportService.checkDaaDuplicate(idvClass, date)){
                //重复, 对每条记录进行查重
                List<Report> details = dateMap.get(date);
                List<Report> remained = new ArrayList<>(details.size());
                for(Report each: details){
                    //对每条记录查重
                    if(reportService.checkSnDuplicate(idvClass, each.getSN())){
                        //重复
                        //添加重复信息
                        payload.addDuplicateError(each);
                        errorCount++;
                        if(errorCount > ERROR_COUNT_THRESHOLD){
                            //失败上线,返回错误
                            payload.setStatus(UploadDetailResponse.Status.TOO_MANY_DUPLICATE_ERROR);
                            return payload;
                        }
                    }else{
                        //将不重复的元素加入新列表
                        remained.add(each);
                    }
                }
                details.clear();
                if(remained.size() >0){
                    dateMap.put(date, remained);
                }else{
                    dateMap.remove(date);
                }

            }
        }

        //清空list,储存准备插入的数据
        list.clear();

        //插入
        for(Date date: dateMap.keySet()){
            List<Report> details = dateMap.get(date);
            for(Report each: details){
                //填充人员类型
                each.setCLASS(idvClass.getLabel());
                //加入
                list.add(each);
            }
        }
        if(list.size() > 0){
            int num = reportService.addBatch(list);
            if(num != list.size()){
                payload.setStatus(UploadDetailResponse.Status.ERROR);
                payload.setMsg("保存数据时出错");
                return payload;
            }

            //上传成功
            payload.setSuccessCount(num);
            payload.setStatus(UploadDetailResponse.Status.OK);

            //更新汇总表
//            Calendar calendar = Calendar.getInstance();
//            ReportUpdateQuery query = new ReportUpdateQuery();
//            for(Date date: dateMap.keySet()){
//                calendar.setTime(date);
//                query.setYear(calendar.get(Calendar.YEAR));
//                query.setMonth(calendar.get(Calendar.MONTH));
//                query.setCLASS(idvClass.getLabel());
//                reportUpdateService.update(reportClass, query);
//
//            }
        }
        return payload;
    }


    @RequestMapping("/uploadDetail")
    @ResponseBody
    public JsonResponse uploadDetail(@RequestParam(value = "reportId")Integer reportId,
                               @RequestParam(value = "classId")Integer classId,
                               @RequestParam(value = "data")String data){
        JsonResponse result = new JsonResponse(ResponseStatus.ERROR);
        logger.debug("报表明细数据上传");
        //logger.debug("reportId=", reportId, "classId=", className);
        //logger.debug("data=", data);
        ReportClass reportClass = ReportClass.get(reportId);
        IndividualClass idvClass = IndividualClass.get(classId);
        if(reportClass == null || idvClass == null || data == null){
            //返回参数错
            logger.debug("错误1");
            return returnParamError(result, null);

        }
        //解析json数据
        ReportService reportService = reportServiceFactory.getReportService(reportClass);
        List<Report> list = (List<Report>) reportService.parseFromJson(reportClass, data);
        if(list == null || list.size() == 0){
            //返回参数错误
            logger.debug("错误2");
            return returnParamError(result, "数据解析错误");
        }


        result.setCode(ResponseStatus.SUCCESS);
        return result;
    }


    @RequestMapping(value="/uploadFile" , method = RequestMethod.POST)
    @ResponseBody
    public JsonResponse uploadFile(@RequestParam(value = "reportId")Integer reportId,
                              @RequestParam(value = "classId")Integer classId,
                                   @RequestParam("file") MultipartFile file)
    {
        JsonResponse result = new JsonResponse(ResponseStatus.ERROR);
        ReportClass reportClass = ReportClass.get(reportId);
        IndividualClass idvClass = IndividualClass.get(classId);
        if(reportClass == null || idvClass == null || file == null){
            //返回参数错
            logger.debug("请求参数错误");
            return returnParamError(result, "请求参数错误");
        }

        List<Report> list = new ArrayList<>(512);
        Report report;
        ReportResolver resolver = ReportResolverFactory.getResolver(reportClass, idvClass);

        InputStream inputStream;
        try{
            inputStream = file.getInputStream();
        }catch (IOException e){
            result.set(ResponseStatus.ERROR, "无法读取上传文件");
            logger.error(e.getMessage());
            return result;
        }
        if(!resolver.begin(inputStream, "GBK")){
            //添加解析错误
            ReportResolverError error = resolver.getResolverError();
            // 错误消息
            result.set(ResponseStatus.DATA_ERROR, "无法解析文件");
            result.setData(error);
            return result;
        }

        //解析
        int errorCount = 0;
        List<ReportResolverError> reportResolverErrors = new ArrayList<>();
        while (resolver.hasNext()){
            report = resolver.next();
            if(report != null){
                list.add(report);
            }else{
                ReportResolverError error = resolver.getResolverError();
                if(error != null){
                    errorCount++;
                    reportResolverErrors.add(error);
                    if(errorCount > ERROR_COUNT_THRESHOLD){
                        //操作错误限制，中断本次上传
                        UploadDetailResponse payload = new UploadDetailResponse();
                        payload.setStatus(UploadDetailResponse.Status.TOO_MANY_RESOLVER_ERROR);
                        result.setData(payload);
                        result.set(ResponseStatus.DATA_ERROR, "无法解析文件");
                        return result;
                    }
                }
            }
        }


        //上传
        UploadDetailResponse payload;
        if(list.size() > 0){
            //上传
            payload = this.upload(list, reportClass, idvClass);

        }else{
            payload = new UploadDetailResponse();
        }
        result.setData(payload);

        //解析错误
        if(reportResolverErrors.size() > 0){
            payload.setResolverErrors(reportResolverErrors);
        }
        //成功上传的数量
        if(payload.getSuccessCount() == 0){
            result.set(ResponseStatus.DATA_ERROR, "没有有效的数据");
        }else{
            result.set(ResponseStatus.SUCCESS, "ok");
        }

        return result;
    }


    @RequestMapping("/selectDistribution")
    @ResponseBody
    public JsonResponse selectDistribution(@RequestParam(value = "reportId")Integer reportId,
                                          @RequestParam(value = "year", required = false)int year){
        JsonResponse result = new JsonResponse(ResponseStatus.ERROR);
        ReportClass reportClass = ReportClass.get(reportId);
        if(reportClass == null || year == 0){
            //返回参数错误
            result.setCode(ResponseStatus.PARAM_ERROR);
            result.setMsg("参数有误");
            return result;
        }

        ReportService reportService = reportServiceFactory.getReportService(reportClass);

        List<Map<String, Object>> data = reportService.selectDistribution(year);
        if (data == null){
            return returnParamError(result, "日期错误");
        }

        result.setData(data);
        result.setCode(ResponseStatus.SUCCESS);
        result.setMsg("ok");

        return  result;
    }

    /**
     * 校验报表统计请求参数
     */
    private void formatPagination(ReportStatisticsQuery query){
        //分页格式化
        int page = query.getPage();
        int size = query.getSize();
        if(page > 0 && size > 0){
            size = size > PAGE_MAX_NUM ? PAGE_MAX_NUM: size;
            int start = (page - 1) * size;
            start = start<0?0:start;
            query.setPagination(start, size);
        }
    }
    private boolean checkStatisticsQuery(ReportClass reportClass, ReportStatisticsQuery query, JsonResponse result){

        if(reportClass == null || query == null){
            //返回参数错误
            result.setCode(ResponseStatus.PARAM_ERROR);
            result.setMsg("无效的报表类型或查询条件");
            return false;
        }

        //检查参数组合
        int idvClassId = query.getIdvClassId();
        if(idvClassId > 0) {
            IndividualClass idvClass = IndividualClass.get(idvClassId);
            if (idvClass == null) {
                result.set(ResponseStatus.PARAM_ERROR, "无效的人员类型");
                return false;
            }
            query.setCLASS(idvClass.getLabel());
        }else{
            query.setCLASS(null);
        }
        //分页检测
        if(query.getPage() > 0 && query.getSize() > 0){
            int start = (query.getPage() - 1) * query.getSize();
            start = start<0?0:start;
            query.setPagination(start, query.getSize());
        }
        return true;
    }
    private boolean checkStatisticsQuery(ReportStatisticsQuery query, JsonResponse result){
        if(query == null){
            //返回参数错误
            result.setCode(ResponseStatus.PARAM_ERROR);
            result.setMsg("无效的报表类型或查询条件");
            return false;
        }

        int reportId = query.getSchemaId();
        if(reportId <= 0){
            result.setCode(ResponseStatus.PARAM_ERROR);
            result.setMsg("无效的报表类型");
            return false;
        }
        ReportClass reportClass = ReportClass.get(reportId);
        if(reportClass == null){
            result.setCode(ResponseStatus.PARAM_ERROR);
            result.setMsg("无效的报表类型");
            return false;
        }

        //检查参数组合
        int idvClassId = query.getIdvClassId();
        if(idvClassId > 0) {
            IndividualClass idvClass = IndividualClass.get(idvClassId);
            if (idvClass == null) {
                result.set(ResponseStatus.PARAM_ERROR, "无效的人员类型");
                return false;
            }
            query.setCLASS(idvClass.getLabel());
        }else{
            query.setCLASS(null);
        }

        //分页检测
        if(query.getPage() > 0 && query.getSize() > 0){
            int start = (query.getPage() - 1) * query.getSize();
            start = start<0?0:start;
            query.setPagination(start, query.getSize());
        }
        return true;
    }
    private boolean checkIdvClass(ReportStatisticsQuery query, JsonResponse result){
        int idvClassId = query.getIdvClassId();
        IndividualClass idvClass = IndividualClass.get(idvClassId);
        if (idvClass == null) {
            result.set(ResponseStatus.PARAM_ERROR, "无效的人员类型");
            return false;
        }
        query.setCLASS(idvClass.getLabel());
        return true;
    }
    private boolean checkReport(ReportStatisticsQuery query, JsonResponse result){
        int reportId = query.getReportId();
        ReportClass reportClass = ReportClass.get(reportId);
        if(reportClass == null){
            result.setCode(ResponseStatus.PARAM_ERROR);
            result.setMsg("无效的数据表类型");
            return false;
        }
        query.setReport(reportClass);
        return true;
    }


    /**
     * 通用拉取数据表统计数据
     * @return
     */
    @RequestMapping("/fetchDataTableSummary")
    @ResponseBody
    public JsonResponse fetchDataTableSummary(ReportStatisticsQuery query){

        JsonResponse result = new JsonResponse(ResponseStatus.ERROR);

        if(!checkReport(query, result)){return result;}
        if(!checkIdvClass(query, result)){return result;}

        //分页格式化
        formatPagination(query);

        System.out.println(query);

        PageBean<Map<String, Object>> pageBean;
        switch (query.getTypeId()){
            case 1:
                pageBean = reportStatisticsService.selectNum(query);
                break;
            case 2:
                pageBean = reportStatisticsService.selectTimes(query);
                break;
            case 3:
                pageBean = reportStatisticsService.selectExpense(query);
                break;
            case 4:
                pageBean = reportStatisticsService.selectPayment(query);
                break;
            default:
                return returnParamError(result, "无效的查询类型");
        }

        result.set(ResponseStatus.SUCCESS, "ok");
        result.setData(pageBean);
        return result;
    }

    /**
     * 查询结算数据
     * @param query @查询条件
     * @return
     */
    @RequestMapping("/selectSettlement")
    @ResponseBody
    public JsonResponse selectSettlement(ReportStatisticsQuery query){
        JsonResponse result = new JsonResponse(ResponseStatus.ERROR);
        if(query.getYearMonth() == null){
            return returnParamError(result, "参数错误");
        }
        formatPagination(query);
        System.out.println(query);
        PageBean<Map<String, Object>> dataset = reportStatisticsService.selectSettlement(query);
        if(dataset == null){
            result.set(ResponseStatus.DATA_ERROR, "没有数据");
            return result;
        }
        result.set(ResponseStatus.SUCCESS, "ok");
        result.setData(dataset);
        return result;

    }

    /**
     * 查询汇总数据-所有费用合计
     */
    @RequestMapping("/selectTotalExpense")
    @ResponseBody
    public JsonResponse selectTotalExpense(ReportStatisticsQuery query){
        JsonResponse result = new JsonResponse(ResponseStatus.ERROR);
        System.out.println(query);

        List<Map<String, Object>> dataset = reportStatisticsService.selectTotalExpense(query);
        if (dataset == null){
            result.set(ResponseStatus.DATA_ERROR, "没有数据");
            return result;
        }
        result.set(ResponseStatus.SUCCESS, "ok");
        result.setData(dataset);
        return result;
    }

    /**
     * 查询汇总数据-所有费用合计
     */
    @RequestMapping("/selectMonthly")
    @ResponseBody
    public JsonResponse selectMonthly(ReportStatisticsQuery query){
        JsonResponse result = new JsonResponse(ResponseStatus.ERROR);

        if(query == null){
            return  returnParamError(result, "参数错误");
        }

        Date yearMonth = query.getYearMonth();
        if(yearMonth == null){
            return  returnParamError(result, "查询日期错误");
        }

        //处理时间参数
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(yearMonth);
        query.setYear(calendar.get(Calendar.YEAR));
        query.setMonth(calendar.get(Calendar.MONTH));
        System.out.println(query);

        List<Map<String, Object>> dataset = reportStatisticsService.selectMonthly(query);
        result.set(ResponseStatus.SUCCESS, "ok");
        result.setData(dataset);
        return result;
    }

    /**
     * 更新统计报表
     */
    @RequestMapping("/updateReport")
    @ResponseBody
    public JsonResponse updateReport(ReportUpdateQuery query){
        JsonResponse result = new JsonResponse(ResponseStatus.ERROR);
        if(query.getYear() <= 0){
            return returnParamError(result, "请指定年份");
        }
        reportUpdateService.updateDepartmentSummary(query);
        reportUpdateService.updateHomeSummary(query);
        reportUpdateService.updateEvaluateSummary(query);
        reportUpdateService.updateSettlementSummary(query);
        reportUpdateService.updateMonthly(query);
        result.set(ResponseStatus.SUCCESS, "ok");
        return result;
    }
}

